package model.data.tableModel.person;

import java.util.Date;

import model.data.interfaces.IFinishable;
import model.data.tableModel.TableControl;
import model.handler.databaseHandling.QueryFactory;
import model.invoicing.DateHandler;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import enums.PaymentType;
import enums.Status;

/**
 * Representation of the table Customer.
 */
public final class Customer implements IFinishable, Comparable<Customer> {

	private final static Logger debug = LogManager.getLogger("DEBUG");
	
	private final int customerID;
	private String name;
	private final PaymentType payment;
	private Person person;
	private int billID;
	private Status status;

	/**
	 * Private constructor because it should be instantiated with the given factory methods.
	 * @param customerID ID of the customer
	 * @param name Name of the customer
	 * @param payment The type how the customer pays
	 * @param customerStatus Status of the customer
	 * @param billID ID of the current bill (changes monthly)
	 * @param person The person representing the customer
	 */
	private Customer(final int customerID, final String name, final PaymentType payment, final Status customerStatus, final int billID, final Person person) {
		assert customerID >=0;
		assert name != null && !"".equals(name);
		assert billID >=0;

		this.name = name;
		this.payment = payment;
		this.person = person;
		this.status = customerStatus;
		this.customerID = customerID;
		this.billID = billID;
	}	

	/**
	 * Creates an already existing Customer. (Is read from the database)
	 * @param ID ID of the customer
	 * @param name Name of the customer
	 * @param payment The type how the customer pays
	 * @param customerStatus Status of the customer
	 * @param billID ID of the current bill (changes monthly)
	 * @param person The person representing the customer
	 * @return The existing Customer
	 */
	public static Customer createExisting(final int ID, final String name, final PaymentType payment, final Status customerStatus, int billID, Person person){
		debug.info("Existing Customer created ID: " + name + " ID: " + ID);
		return new Customer(ID, name, payment, customerStatus, billID, person);
	}
	
	/**
	 * Creates a new Customer.
	 * @param ID ID of the customer
	 * @param name Name of the customer
	 * @param payment The type how the customer pays
	 * @param customerStatus Status of the customer
	 * @param billID ID of the current bill (changes monthly)
	 * @param person The person representing the customer
	 * @return The new Customer
	 * */
	public static Customer createNew(final String name, final PaymentType payment, final Status customerStatus, final Person person){
		int billID = TableControl.getBillCounter();
		int customerID = TableControl.getCentralCounter();
		debug.info("New Customer created ID: " + name + " ID: " + customerID);
		Customer c = new Customer(customerID, name, payment, customerStatus, billID, person);
		c.writeToDB();
		QueryFactory.writeBillToDB(false, billID, null, DateHandler.formatMonthDateToString(new Date()), customerID, Status.TOCALCULATE, -1);
		return c;
	}
	
	@Override
	public String toString(){
		return name;
	}	

	@Override
	public boolean writeToDB() {
		return QueryFactory.writeCustomerToDB(false, customerID, name, payment, person.getPersonID(), status);
	}

	@Override
	public boolean writeUpdateToDB() {
		return QueryFactory.writeCustomerToDB(true, customerID, name, payment, person.getPersonID(), status);
	}
	
	@Override
	public int hashCode() {
		final int prime = 31;
		int result = super.hashCode();
		result = prime * result + billID;
		result = prime * result + customerID;
		result = prime * result + ((name == null) ? 0 : name.hashCode());
		result = prime * result + ((payment == null) ? 0 : payment.hashCode());
		return result;
	}
	
	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (!super.equals(obj))
			return false;
		if (getClass() != obj.getClass())
			return false;
		Customer other = (Customer) obj;
		if (billID != other.billID)
			return false;
		if (customerID != other.customerID)
			return false;
		if (name == null) {
			if (other.name != null)
				return false;
		} else if (!name.equals(other.name))
			return false;
		if (payment != other.payment)
			return false;
		return true;
	}

	@Override
	public int compareTo(Customer o) {
		return this.name.compareToIgnoreCase(o.getName());
	}
	
	/* GETTER AND SETTER BELOW */
	

	public String getName() {
		return name;
	}

	public PaymentType getPayment() {
		return payment;
	}

	public int getCustomerID() {
		return customerID;
	}

	public void setBillID(int billID) {
		assert billID >= 0;
		
		this.billID = billID;
	}

	public Person getPerson() {
		return person;
	}

	public void setName(String name) {
		this.name = name;
	}

	public void setPerson(Person p) {
		this.person = p;
	}

	@Override
	public void setStatus(Status status) {
		this.status = status;
	}
	
	public int getBillID(){
		return billID;
	}
}
